{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 导入必要的模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import absolute_import\n",
    "from __future__ import division\n",
    "from __future__ import print_function\n",
    "\n",
    "import argparse\n",
    "import sys\n",
    "\n",
    "from tensorflow.examples.tutorials.mnist import input_data\n",
    "import tensorflow.contrib.slim as slim\n",
    "\n",
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 导入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting /home/star/tmp/tensorflow/mnist/input_data/train-images-idx3-ubyte.gz\n",
      "Extracting /home/star/tmp/tensorflow/mnist/input_data/train-labels-idx1-ubyte.gz\n",
      "Extracting /home/star/tmp/tensorflow/mnist/input_data/t10k-images-idx3-ubyte.gz\n",
      "Extracting /home/star/tmp/tensorflow/mnist/input_data/t10k-labels-idx1-ubyte.gz\n"
     ]
    }
   ],
   "source": [
    "data_dir = '/home/star/tmp/tensorflow/mnist/input_data'\n",
    "mnist = input_data.read_data_sets(data_dir, one_hot=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义前向传播结构"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = tf.placeholder(tf.float32,[None,784])\n",
    "y_ = tf.placeholder(tf.float32,[None,10])\n",
    "\n",
    "#cast x to 3D\n",
    "x_image = tf.reshape(x,[-1,28,28,1])  #shape of x_image is [N,28,28,1]\n",
    "\n",
    "#conv layer1\n",
    "with tf.name_scope('conv1'):\n",
    "    net = slim.conv2d(x_image,32,[7,7])  #shape of net is [N,28,28,32]   默认激活函数relu，默认padding=‘SAME’，默认权重\n",
    "#pool layer1\n",
    "with tf.name_scope('pool1'):\n",
    "    net = slim.max_pool2d(net,[2,2]) #shape of net is [N,14,14,32]\n",
    "\n",
    "#conv layer2\n",
    "with tf.name_scope('conv2'):\n",
    "    net = slim.conv2d(net,64,[5,5],weights_initializer=\n",
    "                      tf.truncated_normal_initializer(stddev=0.008))  #shape of net is [N,14,14,64]    调节kernel size尺寸和数量\n",
    "#pool layer2                                                        #初始化权重\n",
    "with tf.name_scope('pool2'):\n",
    "    net = slim.max_pool2d(net,[2,2]) #shape of net is [N,7,7,64]\n",
    "\n",
    "#reshape for full connection\n",
    "net = tf.reshape(net,[-1,7*7*64]) #shape of net is [N,7*7*64]\n",
    "\n",
    "#fc layer1\n",
    "with tf.name_scope('fc1'):\n",
    "    net = slim.fully_connected(net,1024)    #shape of net is [N,1024]\n",
    "\n",
    "#dropout layer\n",
    "keep_prob = tf.placeholder('float')\n",
    "with tf.name_scope('dropout'):\n",
    "    net = slim.dropout(net,keep_prob)\n",
    "\n",
    "#fc layer2\n",
    "with tf.name_scope('fc2'):\n",
    "    y = slim.fully_connected(net,10)    #shape of y is [N,10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义损失函数和反向传播"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))     #定义交叉熵损失函数\n",
    "l2_loss = tf.add_n([tf.nn.l2_loss(w) for w in tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)])\n",
    "total_loss = cross_entropy + 7e-5*l2_loss   #加入l2正则项，调节正则化因子\n",
    "\n",
    "learning_rate = tf.placeholder('float')\n",
    "train_step = tf.train.AdamOptimizer(learning_rate).minimize(total_loss)\n",
    "\n",
    "correct_prediction = tf.equal(tf.argmax(y,axis=1),tf.argmax(y_,axis=1))  #shape of correct_prediction is [N]\n",
    "accuracy = tf.reduce_mean(tf.cast(correct_prediction,'float'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 生成会话并训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step 100,train_accuracy: 0.840000,test_accuracy: 0.837200\n",
      "step 200,train_accuracy: 0.960000,test_accuracy: 0.946800\n",
      "step 300,train_accuracy: 0.980000,test_accuracy: 0.962900\n",
      "step 400,train_accuracy: 0.960000,test_accuracy: 0.970700\n",
      "step 500,train_accuracy: 0.980000,test_accuracy: 0.974400\n",
      "step 600,train_accuracy: 0.980000,test_accuracy: 0.976900\n",
      "step 700,train_accuracy: 0.980000,test_accuracy: 0.981400\n",
      "step 800,train_accuracy: 0.970000,test_accuracy: 0.980600\n",
      "step 900,train_accuracy: 0.960000,test_accuracy: 0.983700\n",
      "step 1000,train_accuracy: 0.970000,test_accuracy: 0.984100\n",
      "step 1100,train_accuracy: 0.990000,test_accuracy: 0.983500\n",
      "step 1200,train_accuracy: 1.000000,test_accuracy: 0.984200\n",
      "step 1300,train_accuracy: 0.980000,test_accuracy: 0.983700\n",
      "step 1400,train_accuracy: 1.000000,test_accuracy: 0.987100\n",
      "step 1500,train_accuracy: 0.980000,test_accuracy: 0.988000\n",
      "step 1600,train_accuracy: 0.990000,test_accuracy: 0.989000\n",
      "step 1700,train_accuracy: 0.990000,test_accuracy: 0.988100\n",
      "step 1800,train_accuracy: 1.000000,test_accuracy: 0.988800\n",
      "step 1900,train_accuracy: 1.000000,test_accuracy: 0.989200\n",
      "step 2000,train_accuracy: 0.990000,test_accuracy: 0.989700\n",
      "step 2100,train_accuracy: 1.000000,test_accuracy: 0.989900\n",
      "step 2200,train_accuracy: 0.980000,test_accuracy: 0.989400\n",
      "step 2300,train_accuracy: 0.990000,test_accuracy: 0.989900\n",
      "step 2400,train_accuracy: 1.000000,test_accuracy: 0.990400\n",
      "step 2500,train_accuracy: 0.990000,test_accuracy: 0.989700\n",
      "step 2600,train_accuracy: 0.980000,test_accuracy: 0.989900\n",
      "step 2700,train_accuracy: 0.980000,test_accuracy: 0.990300\n",
      "step 2800,train_accuracy: 1.000000,test_accuracy: 0.990500\n",
      "step 2900,train_accuracy: 1.000000,test_accuracy: 0.990200\n",
      "step 3000,train_accuracy: 1.000000,test_accuracy: 0.990800\n"
     ]
    }
   ],
   "source": [
    "with tf.Session() as sess:\n",
    "    init = tf.global_variables_initializer()\n",
    "    sess.run(init)\n",
    "    \n",
    "    for step in range(3000):\n",
    "        batch_x,batch_y = mnist.train.next_batch(100)\n",
    "        if step<1600:                      #调整学习率\n",
    "            learning_rate1 = 2e-4\n",
    "        else:\n",
    "            learning_rate1 = 4e-5\n",
    "        sess.run(train_step,feed_dict={x:batch_x,y_:batch_y,keep_prob:0.6,learning_rate:learning_rate1})  #添加dropout层能大幅提高准确率\n",
    "        \n",
    "        if (step+1)%100 == 0:\n",
    "            train_accuracy = sess.run(accuracy,feed_dict={x:batch_x,y_:batch_y,keep_prob:1.0})\n",
    "            test_accuracy = sess.run(accuracy,feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0})\n",
    "            print('step %d,train_accuracy: %f,test_accuracy: %f'%(step+1,train_accuracy,test_accuracy))\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
